defold_log("sdk_windows.cmake:")

# Detect Windows toolchain and SDK in this order:
# 1) Prepackaged toolchain under ${DEFOLD_SDK_ROOT}/ext/SDKs (aka tmp/dynamo_home/ext/SDKs)
# 2) Locally installed Visual Studio
# 3) Locally installed LLVM/Clang (clang-cl/clang++)
#
# Results:
# - Sets CMAKE_{C,CXX}_COMPILER when not already provided
# - Tries to detect a Windows SDK version and sets CMAKE_SYSTEM_VERSION

if(NOT WIN32)
    message(DEBUG "sdk_windows: Non-Windows host; nothing to do")
    return()
endif()

set(_DEFOLD_WIN_ARCH "x64")
if(DEFINED TARGET_PLATFORM)
    if(TARGET_PLATFORM MATCHES "(^|-)x86($|-)" OR TARGET_PLATFORM MATCHES "x86-win32")
        set(_DEFOLD_WIN_ARCH "x86")
    endif()
endif()

set(_FOUND_MSVC_CL "")
set(_FOUND_CLANG_CL "")
set(_FOUND_LLVM_CLANGXX "")
set(_FOUND_LLVM_CLANG   "")
set(_FOUND_WINSDK_VERSION "")
set(_FOUND_PACKAGED_TOOLCHAIN FALSE)


# Helper to pick latest directory path from a list of paths
function(_defold_pick_latest_dir OUT_VAR)
    set(dirs ${ARGN})
    if(dirs)
        # Use natural sorting so versioned directory names order correctly
        list(SORT dirs COMPARE NATURAL)
        list(REVERSE dirs)
        list(GET dirs 0 _latest)
        set(${OUT_VAR} "${_latest}" PARENT_SCOPE)
    endif()
endfunction()


# Helper: detect clang-cl.exe under a Visual Studio root
function(_defold_detect_clang_cl_from_vsroot VSROOT ARCH OUT_PATH)
    set(${OUT_PATH} "" PARENT_SCOPE)
    if(NOT EXISTS "${VSROOT}")
        return()
    endif()
    if(ARCH STREQUAL "x64")
        set(_globs "${VSROOT}/VC/Tools/Llvm/x64/bin/clang-cl.exe")
    else()
        set(_globs "${VSROOT}/VC/Tools/Llvm/x86/bin/clang-cl.exe")
    endif()
    file(GLOB _matches ${_globs})
    if(_matches)
        _defold_pick_latest_dir(_best ${_matches})
        if(_best)
            set(${OUT_PATH} "${_best}" PARENT_SCOPE)
        endif()
    endif()
endfunction()

# Helper: locate rc.exe and mt.exe inside a Windows Kits root
function(_defold_locate_winsdk_tools_in_root ROOT VER ARCH OUT_RC OUT_MT)
    set(_rc "")
    set(_mt "")
    if(NOT EXISTS "${ROOT}")
        set(${OUT_RC} "" PARENT_SCOPE)
        set(${OUT_MT} "" PARENT_SCOPE)
        return()
    endif()

    foreach(_winsdk_layout "Windows Kits" "WindowsKits")
        if(_rc AND _mt)
            break()
        endif()
        set(_bin_root "${ROOT}/${_winsdk_layout}/10/bin")
        if(EXISTS "${_bin_root}")
            # Prefer versioned layout: .../10/bin/<VER>/<ARCH>/
            set(_ver_dir "${_bin_root}/${VER}")
            if(EXISTS "${_ver_dir}")
                set(_rc_candidate "${_ver_dir}/${ARCH}/rc.exe")
                set(_mt_candidate "${_ver_dir}/${ARCH}/mt.exe")
                if(NOT _rc AND EXISTS "${_rc_candidate}")
                    set(_rc "${_rc_candidate}")
                endif()
                if(NOT _mt AND EXISTS "${_mt_candidate}")
                    set(_mt "${_mt_candidate}")
                endif()
            endif()
            # Fallback non-versioned layout: .../10/bin/<ARCH>/
            if(NOT _rc)
                set(_rc_candidate2 "${_bin_root}/${ARCH}/rc.exe")
                if(EXISTS "${_rc_candidate2}")
                    set(_rc "${_rc_candidate2}")
                endif()
            endif()
            if(NOT _mt)
                set(_mt_candidate2 "${_bin_root}/${ARCH}/mt.exe")
                if(EXISTS "${_mt_candidate2}")
                    set(_mt "${_mt_candidate2}")
                endif()
            endif()
        endif()
    endforeach()

    set(${OUT_RC} "${_rc}" PARENT_SCOPE)
    set(${OUT_MT} "${_mt}" PARENT_SCOPE)
endfunction()

# Helper: given a cl.exe path, locate the MSVC lib directory that contains LIBCMT.lib
function(_defold_locate_msvc_lib_dir_from_cl CL_PATH ARCH OUT_LIB_DIR)
    set(${OUT_LIB_DIR} "" PARENT_SCOPE)
    if(NOT EXISTS "${CL_PATH}")
        return()
    endif()
    # Normalize and walk up to VC/Tools/MSVC/<ver>
    file(REAL_PATH "${CL_PATH}" _cl_real)
    cmake_path(GET _cl_real PARENT_PATH _cl_dir)       # .../bin/Host*/<arch>
    cmake_path(GET _cl_dir  PARENT_PATH _host_dir)     # .../bin/Host*
    cmake_path(GET _host_dir PARENT_PATH _bin_dir)     # .../bin
    cmake_path(GET _bin_dir  PARENT_PATH _msvc_ver_dir)# .../VC/Tools/MSVC/<ver>

    set(_candidates
        "${_msvc_ver_dir}/lib/${ARCH}"
        "${_msvc_ver_dir}/lib/onecore/${ARCH}"
    )
    foreach(_cand IN LISTS _candidates)
        if(EXISTS "${_cand}/libcmt.lib")
            set(${OUT_LIB_DIR} "${_cand}" PARENT_SCOPE)
            return()
        endif()
    endforeach()
endfunction()

# Helper: given a cl.exe path, locate the MSVC include directory that contains vcruntime.h
function(_defold_locate_msvc_include_dir_from_cl CL_PATH OUT_INC_DIR)
    set(${OUT_INC_DIR} "" PARENT_SCOPE)
    if(NOT EXISTS "${CL_PATH}")
        return()
    endif()
    file(REAL_PATH "${CL_PATH}" _cl_real)
    cmake_path(GET _cl_real PARENT_PATH _cl_dir)       # .../bin/Host*/<arch>
    cmake_path(GET _cl_dir  PARENT_PATH _host_dir)     # .../bin/Host*
    cmake_path(GET _host_dir PARENT_PATH _bin_dir)     # .../bin
    cmake_path(GET _bin_dir  PARENT_PATH _msvc_ver_dir)# .../VC/Tools/MSVC/<ver>
    set(_inc_dir "${_msvc_ver_dir}/include")
    if(EXISTS "${_inc_dir}/vcruntime.h")
        set(${OUT_INC_DIR} "${_inc_dir}" PARENT_SCOPE)
    endif()
endfunction()

# Helper: locate UM and UCRT lib dirs in a Windows Kits root
function(_defold_locate_winsdk_lib_dirs_in_root ROOT VER ARCH OUT_UM_DIR OUT_UCRT_DIR)
    set(_um_dir "")
    set(_ucrt_dir "")
    foreach(_winsdk_layout "Windows Kits" "WindowsKits")
        if(_um_dir AND _ucrt_dir)
            break()
        endif()
        set(_lib_root "${ROOT}/${_winsdk_layout}/10/Lib/${VER}")
        if(EXISTS "${_lib_root}")
            set(_um_candidate "${_lib_root}/um/${ARCH}")
            if(EXISTS "${_um_candidate}")
                set(_um_dir "${_um_candidate}")
            endif()
            set(_ucrt_candidate "${_lib_root}/ucrt/${ARCH}")
            if(EXISTS "${_ucrt_candidate}")
                set(_ucrt_dir "${_ucrt_candidate}")
            endif()
        endif()
    endforeach()
    set(${OUT_UM_DIR} "${_um_dir}" PARENT_SCOPE)
    set(${OUT_UCRT_DIR} "${_ucrt_dir}" PARENT_SCOPE)
endfunction()

# Helper: detect Windows SDK version under a root (Windows Kits/10/Include/<ver>)
function(_defold_detect_winsdk_from_root ROOT OUT_VER)
    set(${OUT_VER} "" PARENT_SCOPE)
    if(NOT EXISTS "${ROOT}")
        return()
    endif()
    set(_best_ver "")
    foreach(_winsdk_layout "Windows Kits" "WindowsKits")
        if(_best_ver)
            break()
        endif()
        set(_inc_root "${ROOT}/${_winsdk_layout}/10/Include")
        if(EXISTS "${_inc_root}")
            file(GLOB _sdk_vers RELATIVE "${_inc_root}" "${_inc_root}/*")
            if(_sdk_vers)
                _defold_pick_latest_dir(_latest_ver ${_sdk_vers})
                if(_latest_ver)
                    set(_best_ver "${_latest_ver}")
                endif()
            endif()
        endif()
    endforeach()
    if(_best_ver)
        set(${OUT_VER} "${_best_ver}" PARENT_SCOPE)
    endif()
endfunction()

# Helper: detect cl.exe under a Visual Studio root
function(_defold_detect_msvc_cl_from_vsroot VSROOT ARCH OUT_PATH)
    set(${OUT_PATH} "" PARENT_SCOPE)
    if(NOT EXISTS "${VSROOT}")
        return()
    endif()
    if(ARCH STREQUAL "x64")
        set(_cl_globs "${VSROOT}/VC/Tools/MSVC/*/bin/Hostx64/x64/cl.exe")
    else()
        set(_cl_globs "${VSROOT}/VC/Tools/MSVC/*/bin/Hostx86/x86/cl.exe")
    endif()
    foreach(_pat IN LISTS _cl_globs)
        file(GLOB _matches ${_pat})
        if(_matches)
            _defold_pick_latest_dir(_best ${_matches})
            if(_best)
                set(${OUT_PATH} "${_best}" PARENT_SCOPE)
                return()
            endif()
        endif()
    endforeach()
endfunction()

#############################################
# Visual Studio roots and detection (packaged first)
set(_VS_PACKAGED_ROOTS "")
set(_VS_PACKAGED_SEARCH_DIRS "")

# Always probe the repo-local tmp/dynamo_home first to prefer packaged toolchains
get_filename_component(_DEFOLD_REPO_ROOT "${CMAKE_CURRENT_LIST_DIR}/../.." ABSOLUTE)
set(_DEFOLD_TMP_DYNAMO_HOME "${_DEFOLD_REPO_ROOT}/tmp/dynamo_home")
if(EXISTS "${_DEFOLD_TMP_DYNAMO_HOME}/ext/SDKs")
    list(APPEND _VS_PACKAGED_SEARCH_DIRS "${_DEFOLD_TMP_DYNAMO_HOME}/ext/SDKs")
endif()

if(DEFINED DEFOLD_SDK_ROOT)
    set(_SDKS_DIR "${DEFOLD_SDK_ROOT}/ext/SDKs")
    if(EXISTS "${_SDKS_DIR}")
        list(APPEND _VS_PACKAGED_SEARCH_DIRS "${_SDKS_DIR}")
    endif()
endif()

list(REMOVE_DUPLICATES _VS_PACKAGED_SEARCH_DIRS)

foreach(_sdks_dir IN LISTS _VS_PACKAGED_SEARCH_DIRS)
    defold_collect_packaged_roots("${_sdks_dir}" _packaged_level1)
    if(_packaged_level1)
        list(APPEND _VS_PACKAGED_ROOTS ${_packaged_level1})
    endif()
    file(GLOB _packaged_vs_roots LIST_DIRECTORIES TRUE "${_sdks_dir}/*/MicrosoftVisualStudio*")
    if(_packaged_vs_roots)
        list(APPEND _VS_PACKAGED_ROOTS ${_packaged_vs_roots})
    endif()
endforeach()

list(REMOVE_DUPLICATES _VS_PACKAGED_ROOTS)

set(_VS_CANDIDATE_ROOTS "")
if(_VS_PACKAGED_ROOTS)
    list(APPEND _VS_CANDIDATE_ROOTS ${_VS_PACKAGED_ROOTS})
endif()

# 1) Scan packaged Visual Studio roots first
foreach(_vs IN LISTS _VS_PACKAGED_ROOTS)
    if(NOT _FOUND_MSVC_CL)
        _defold_detect_msvc_cl_from_vsroot("${_vs}" "${_DEFOLD_WIN_ARCH}" _cl)
        if(_cl)
            set(_FOUND_MSVC_CL "${_cl}")
        endif()
    endif()
    if(NOT _FOUND_CLANG_CL)
        _defold_detect_clang_cl_from_vsroot("${_vs}" "${_DEFOLD_WIN_ARCH}" _clangcl)
        if(_clangcl)
            set(_FOUND_CLANG_CL "${_clangcl}")
        endif()
    endif()
endforeach()

# 2) If not found yet, add local Visual Studio roots
set(_VS_LOCAL_ROOTS "")
find_program(_VSWHERE vswhere HINTS "C:/Program Files (x86)/Microsoft Visual Studio/Installer")
if(_VSWHERE)
    execute_process(COMMAND "${_VSWHERE}" -latest -requires Microsoft.VisualStudio.Component.VC.Tools.x86.x64 -property installationPath
                    OUTPUT_VARIABLE _VS_INSTALL
                    OUTPUT_STRIP_TRAILING_WHITESPACE
                    ERROR_QUIET)
    if(_VS_INSTALL AND EXISTS "${_VS_INSTALL}")
        list(APPEND _VS_LOCAL_ROOTS "${_VS_INSTALL}")
    endif()
endif()

list(APPEND _VS_LOCAL_ROOTS
    "C:/Program Files (x86)/Microsoft Visual Studio/2022/BuildTools"
    "C:/Program Files (x86)/Microsoft Visual Studio/2022/Community"
    "C:/Program Files (x86)/Microsoft Visual Studio/2019/BuildTools"
    "C:/Program Files (x86)/Microsoft Visual Studio/2019/Community")
list(REMOVE_DUPLICATES _VS_LOCAL_ROOTS)

if(_VS_LOCAL_ROOTS)
    list(APPEND _VS_CANDIDATE_ROOTS ${_VS_LOCAL_ROOTS})
    list(REMOVE_DUPLICATES _VS_CANDIDATE_ROOTS)
endif()

if(NOT _FOUND_MSVC_CL OR NOT _FOUND_CLANG_CL)
    foreach(_vs IN LISTS _VS_LOCAL_ROOTS)
        if(NOT _FOUND_MSVC_CL)
            _defold_detect_msvc_cl_from_vsroot("${_vs}" "${_DEFOLD_WIN_ARCH}" _cl)
            if(_cl)
                set(_FOUND_MSVC_CL "${_cl}")
            endif()
        endif()
        if(NOT _FOUND_CLANG_CL)
            _defold_detect_clang_cl_from_vsroot("${_vs}" "${_DEFOLD_WIN_ARCH}" _clangcl)
            if(_clangcl)
                set(_FOUND_CLANG_CL "${_clangcl}")
            endif()
        endif()
    endforeach()
endif()

# Detect Windows SDK version from the same roots or system
if(NOT _FOUND_WINSDK_VERSION)
    foreach(_root IN LISTS _VS_CANDIDATE_ROOTS)
        if(NOT _FOUND_WINSDK_VERSION)
            _defold_detect_winsdk_from_root("${_root}" _ver)
            if(_ver)
                set(_FOUND_WINSDK_VERSION "${_ver}")
            endif()
        endif()
    endforeach()
endif()
if(NOT _FOUND_WINSDK_VERSION)
    foreach(_sys IN ITEMS "C:/Program Files (x86)" "C:/Program Files")
        if(NOT _FOUND_WINSDK_VERSION)
            _defold_detect_winsdk_from_root("${_sys}" _ver_sys)
            if(_ver_sys)
                set(_FOUND_WINSDK_VERSION "${_ver_sys}")
            endif()
        endif()
    endforeach()
endif()

# Local LLVM/Clang (clang++) if nothing else found
if(NOT _FOUND_CLANG_CL AND NOT _FOUND_MSVC_CL AND NOT _FOUND_LLVM_CLANGXX)
    # Prefer locally installed Visual Studio over LLVM/Clang (handled above)
    # Now look for a local LLVM install (prefer clang-cl)
    find_program(_CLANGCL clang-cl HINTS
        "C:/Program Files/LLVM/bin"
        "C:/Program Files (x86)/LLVM/bin"
    )
    if(_CLANGCL)
        set(_FOUND_CLANG_CL "${_CLANGCL}")
    else()
        find_program(_CLANGXX clang++ HINTS
            "C:/Program Files/LLVM/bin"
            "C:/Program Files (x86)/LLVM/bin"
        )
        if(_CLANGXX)
            set(_FOUND_LLVM_CLANGXX "${_CLANGXX}")
            get_filename_component(_clang_dir "${_CLANGXX}" DIRECTORY)
            find_program(_CLANG clang HINTS "${_clang_dir}")
            if(_CLANG)
                set(_FOUND_LLVM_CLANG "${_CLANG}")
            endif()
        endif()
    endif()

    # Try Git for Windows LLVM bundle (sometimes installed via VSCode toolchains)
    if(NOT _FOUND_LLVM_CLANGXX)
        find_program(_CLANGCL2 clang-cl)
        if(_CLANGCL2 AND NOT _FOUND_CLANG_CL)
            set(_FOUND_CLANG_CL "${_CLANGCL2}")
        endif()
        if(NOT _FOUND_CLANG_CL)
            find_program(_CLANGXX2 clang++)
            if(_CLANGXX2)
                set(_FOUND_LLVM_CLANGXX "${_CLANGXX2}")
            endif()
            find_program(_CLANG2 clang)
            if(NOT _FOUND_LLVM_CLANG AND _CLANG2)
                set(_FOUND_LLVM_CLANG "${_CLANG2}")
            endif()
        endif()
    endif()

    # Windows SDK version from system if not set
    if(NOT _FOUND_WINSDK_VERSION)
        _defold_detect_winsdk_from_root("C:/Program Files (x86)" _ver2)
        if(_ver2)
            set(_FOUND_WINSDK_VERSION "${_ver2}")
        endif()
    endif()
endif()

# As a last resort, if no Windows SDK version has been detected yet, try the system install
if(NOT _FOUND_WINSDK_VERSION)
    _defold_detect_winsdk_from_root("C:/Program Files (x86)" _ver3)
    if(_ver3)
        set(_FOUND_WINSDK_VERSION "${_ver3}")
    endif()
endif()

# Finalize: choose compilers respecting requested order:
# - Prefer packaged toolchains (handled by skipping local detection when packaged is present)
# - Otherwise prefer locally installed Visual Studio over local LLVM/Clang

if(_FOUND_MSVC_CL)
    defold_log("sdk_windows: Using MSVC cl: ${_FOUND_MSVC_CL}")
    # Cache discovered MSVC cl path
    set(DEFOLD_MSVC_CL "${_FOUND_MSVC_CL}" CACHE FILEPATH "Path to cl.exe (MSVC)" FORCE)
    # Export alias for compatibility with consumers expecting MSVC_CL
    set(MSVC_CL "${_FOUND_MSVC_CL}" CACHE FILEPATH "Path to MSVC cl.exe" FORCE)
    if(NOT CMAKE_C_COMPILER)
        set(CMAKE_C_COMPILER "${_FOUND_MSVC_CL}" CACHE FILEPATH "MSVC C compiler" FORCE)
    endif()
    if(NOT CMAKE_CXX_COMPILER)
        set(CMAKE_CXX_COMPILER "${_FOUND_MSVC_CL}" CACHE FILEPATH "MSVC C++ compiler" FORCE)
    endif()
elseif(_FOUND_CLANG_CL)
    defold_log("sdk_windows: Using clang-cl: ${_FOUND_CLANG_CL}")
    if(NOT CMAKE_C_COMPILER)
        set(CMAKE_C_COMPILER "${_FOUND_CLANG_CL}" CACHE FILEPATH "LLVM C compiler (clang-cl)" FORCE)
    endif()
    if(NOT CMAKE_CXX_COMPILER)
        set(CMAKE_CXX_COMPILER "${_FOUND_CLANG_CL}" CACHE FILEPATH "LLVM C++ compiler (clang-cl)" FORCE)
    endif()
elseif(_FOUND_LLVM_CLANGXX)
    defold_log("sdk_windows: Using LLVM toolchain: ${_FOUND_LLVM_CLANGXX}")
    if(NOT CMAKE_CXX_COMPILER)
        set(CMAKE_CXX_COMPILER "${_FOUND_LLVM_CLANGXX}" CACHE FILEPATH "LLVM C++ compiler" FORCE)
    endif()
    if(NOT CMAKE_C_COMPILER)
        if(_FOUND_LLVM_CLANGXX MATCHES "clang-cl\.exe$")
            set(CMAKE_C_COMPILER "${_FOUND_LLVM_CLANGXX}" CACHE FILEPATH "LLVM C compiler (clang-cl)" FORCE)
        elseif(_FOUND_LLVM_CLANG)
            set(CMAKE_C_COMPILER "${_FOUND_LLVM_CLANG}" CACHE FILEPATH "LLVM clang" FORCE)
        else()
            find_program(_FALLBACK_CLANG clang)
            if(_FALLBACK_CLANG)
                set(CMAKE_C_COMPILER "${_FALLBACK_CLANG}" CACHE FILEPATH "LLVM clang" FORCE)
            endif()
        endif()
    endif()
else()
    message(WARNING "sdk_windows: No suitable MSVC or LLVM toolchain found. CMake default compilers will be used.")
endif()

# Set Windows SDK version if discovered (helps CMake locate SDK libs/headers)
if(_FOUND_WINSDK_VERSION)
    # CMake uses CMAKE_SYSTEM_VERSION to control chosen Windows SDK
    set(CMAKE_SYSTEM_VERSION "${_FOUND_WINSDK_VERSION}" CACHE STRING "Windows SDK version" FORCE)
    defold_log("sdk_windows: Windows SDK version: ${CMAKE_SYSTEM_VERSION}")
    # Cache discovered WinSDK version
    set(DEFOLD_WINSDK_VERSION "${_FOUND_WINSDK_VERSION}" CACHE STRING "Detected Windows SDK version" FORCE)
endif()

# Locate rc.exe and mt.exe inside the chosen Windows Kits folder
if(_FOUND_WINSDK_VERSION)
    set(_WSDK_CANDIDATE_ROOTS "")
    if(DEFINED DEFOLD_SDK_ROOT)
        set(_SDKS_DIR "${DEFOLD_SDK_ROOT}/ext/SDKs")
        if(EXISTS "${_SDKS_DIR}")
            defold_collect_packaged_roots("${_SDKS_DIR}" _wsdk_roots)
            list(APPEND _WSDK_CANDIDATE_ROOTS ${_wsdk_roots})
        endif()
    endif()
    # Always include system locations
    list(APPEND _WSDK_CANDIDATE_ROOTS "C:/Program Files (x86)" "C:/Program Files")
    list(REMOVE_DUPLICATES _WSDK_CANDIDATE_ROOTS)

    set(_FOUND_RC_EXE "")
    set(_FOUND_MT_EXE "")
    foreach(_root IN LISTS _WSDK_CANDIDATE_ROOTS)
        if(NOT _FOUND_RC_EXE OR NOT _FOUND_MT_EXE)
            _defold_locate_winsdk_tools_in_root("${_root}" "${_FOUND_WINSDK_VERSION}" "${_DEFOLD_WIN_ARCH}" _rc _mt)
            if(NOT _FOUND_RC_EXE AND _rc)
                set(_FOUND_RC_EXE "${_rc}")
            endif()
            if(NOT _FOUND_MT_EXE AND _mt)
                set(_FOUND_MT_EXE "${_mt}")
            endif()
        endif()
    endforeach()

    if(_FOUND_RC_EXE)
        set(CMAKE_RC_COMPILER "${_FOUND_RC_EXE}" CACHE FILEPATH "Windows Resource Compiler (rc.exe)" FORCE)
        defold_log("sdk_windows: Using rc.exe: ${CMAKE_RC_COMPILER}")
        set(DEFOLD_WINSDK_RC "${_FOUND_RC_EXE}" CACHE FILEPATH "Windows Resource Compiler (rc.exe)" FORCE)
    endif()
    if(_FOUND_MT_EXE)
        set(CMAKE_MT "${_FOUND_MT_EXE}" CACHE FILEPATH "Windows Manifest Tool (mt.exe)" FORCE)
        defold_log("sdk_windows: Using mt.exe: ${CMAKE_MT}")
        set(DEFOLD_WINSDK_MT "${_FOUND_MT_EXE}" CACHE FILEPATH "Windows Manifest Tool (mt.exe)" FORCE)
    endif()
endif()

# Locate base Windows libraries (e.g. kernel32.lib) inside the chosen Windows Kits folder
if(_FOUND_WINSDK_VERSION)
    set(_WSDK_CANDIDATE_ROOTS_LIB "")
    if(DEFINED DEFOLD_SDK_ROOT)
        set(_SDKS_DIR "${DEFOLD_SDK_ROOT}/ext/SDKs")
        if(EXISTS "${_SDKS_DIR}")
            list(APPEND _WSDK_CANDIDATE_ROOTS_LIB "${_SDKS_DIR}")
            file(GLOB _wsdk_children2 "${_SDKS_DIR}/*")
            foreach(_child IN LISTS _wsdk_children2)
                if(IS_DIRECTORY "${_child}")
                    list(APPEND _WSDK_CANDIDATE_ROOTS_LIB "${_child}")
                endif()
            endforeach()
        endif()
    endif()
    list(APPEND _WSDK_CANDIDATE_ROOTS_LIB "C:/Program Files (x86)" "C:/Program Files")
    list(REMOVE_DUPLICATES _WSDK_CANDIDATE_ROOTS_LIB)

    set(DEFOLD_WINSDK_LIB_UM_DIR "")
    set(DEFOLD_WINSDK_LIB_UCRT_DIR "")

    foreach(_root IN LISTS _WSDK_CANDIDATE_ROOTS_LIB)
        if(NOT DEFOLD_WINSDK_LIB_UM_DIR OR NOT DEFOLD_WINSDK_LIB_UCRT_DIR)
            _defold_locate_winsdk_lib_dirs_in_root("${_root}" "${_FOUND_WINSDK_VERSION}" "${_DEFOLD_WIN_ARCH}" _um _ucrt)
            if(NOT DEFOLD_WINSDK_LIB_UM_DIR AND _um)
                set(DEFOLD_WINSDK_LIB_UM_DIR "${_um}")
            endif()
            if(NOT DEFOLD_WINSDK_LIB_UCRT_DIR AND _ucrt)
                set(DEFOLD_WINSDK_LIB_UCRT_DIR "${_ucrt}")
            endif()
        endif()
    endforeach()

    if(DEFOLD_WINSDK_LIB_UM_DIR)
        defold_log("sdk_windows: WindowsKits UM libs: ${DEFOLD_WINSDK_LIB_UM_DIR}")
        list(APPEND CMAKE_LIBRARY_PATH "${DEFOLD_WINSDK_LIB_UM_DIR}")
        set(DEFOLD_WINSDK_LIB_UM_DIR "${DEFOLD_WINSDK_LIB_UM_DIR}" CACHE PATH "WindowsKits UM lib directory" FORCE)
    endif()
    if(DEFOLD_WINSDK_LIB_UCRT_DIR)
        defold_log("sdk_windows: WindowsKits UCRT libs: ${DEFOLD_WINSDK_LIB_UCRT_DIR}")
        list(APPEND CMAKE_LIBRARY_PATH "${DEFOLD_WINSDK_LIB_UCRT_DIR}")
        set(DEFOLD_WINSDK_LIB_UCRT_DIR "${DEFOLD_WINSDK_LIB_UCRT_DIR}" CACHE PATH "WindowsKits UCRT lib directory" FORCE)
    endif()

    # Collect /LIBPATH flags for linker (affects try_compile checks too)
    if(NOT DEFINED _DEFOLD_LINK_LIBPATH_FLAGS)
        set(_DEFOLD_LINK_LIBPATH_FLAGS "")
    endif()
    if(DEFOLD_WINSDK_LIB_UCRT_DIR)
        list(APPEND _DEFOLD_LINK_LIBPATH_FLAGS "/LIBPATH:\"${DEFOLD_WINSDK_LIB_UCRT_DIR}\"")
    endif()
    if(DEFOLD_WINSDK_LIB_UM_DIR)
        list(APPEND _DEFOLD_LINK_LIBPATH_FLAGS "/LIBPATH:\"${DEFOLD_WINSDK_LIB_UM_DIR}\"")
    endif()
endif()

# Locate Windows Kits include directories and add to include paths and compiler flags
if(_FOUND_WINSDK_VERSION)
    set(DEFOLD_WINSDK_INCLUDE_SHARED "")
    set(DEFOLD_WINSDK_INCLUDE_UM "")
    set(DEFOLD_WINSDK_INCLUDE_UCRT "")
    set(DEFOLD_WINSDK_INCLUDE_WINRT "")

    set(_WSDK_INC_CANDIDATE_ROOTS "")
    if(DEFINED DEFOLD_SDK_ROOT)
        set(_SDKS_DIR "${DEFOLD_SDK_ROOT}/ext/SDKs")
        if(EXISTS "${_SDKS_DIR}")
            list(APPEND _WSDK_INC_CANDIDATE_ROOTS "${_SDKS_DIR}")
            file(GLOB _wsdk_children_inc "${_SDKS_DIR}/*")
            foreach(_child IN LISTS _wsdk_children_inc)
                if(IS_DIRECTORY "${_child}")
                    list(APPEND _WSDK_INC_CANDIDATE_ROOTS "${_child}")
                endif()
            endforeach()
        endif()
    endif()
    list(APPEND _WSDK_INC_CANDIDATE_ROOTS "C:/Program Files (x86)" "C:/Program Files")
    list(REMOVE_DUPLICATES _WSDK_INC_CANDIDATE_ROOTS)

    foreach(_root IN LISTS _WSDK_INC_CANDIDATE_ROOTS)
        foreach(_winsdk_layout "Windows Kits" "WindowsKits")
            if(NOT (DEFOLD_WINSDK_INCLUDE_SHARED AND DEFOLD_WINSDK_INCLUDE_UM AND DEFOLD_WINSDK_INCLUDE_UCRT))
                set(_inc_root "${_root}/${_winsdk_layout}/10/Include/${_FOUND_WINSDK_VERSION}")
                if(EXISTS "${_inc_root}")
                    if(NOT DEFOLD_WINSDK_INCLUDE_SHARED AND EXISTS "${_inc_root}/shared")
                        set(DEFOLD_WINSDK_INCLUDE_SHARED "${_inc_root}/shared")
                    endif()
                    if(NOT DEFOLD_WINSDK_INCLUDE_UM AND EXISTS "${_inc_root}/um")
                        set(DEFOLD_WINSDK_INCLUDE_UM "${_inc_root}/um")
                    endif()
                    if(NOT DEFOLD_WINSDK_INCLUDE_UCRT AND EXISTS "${_inc_root}/ucrt")
                        set(DEFOLD_WINSDK_INCLUDE_UCRT "${_inc_root}/ucrt")
                    endif()
                    if(NOT DEFOLD_WINSDK_INCLUDE_WINRT AND EXISTS "${_inc_root}/winrt")
                        set(DEFOLD_WINSDK_INCLUDE_WINRT "${_inc_root}/winrt")
                    endif()
                endif()
            endif()
        endforeach()
    endforeach()

    # Log and add to include search paths
    set(_DEFOLD_INCLUDE_FLAGS "")
    set(_DEFOLD_INC_DIRS)
    foreach(_dir_var DEFOLD_WINSDK_INCLUDE_SHARED DEFOLD_WINSDK_INCLUDE_UCRT DEFOLD_WINSDK_INCLUDE_UM DEFOLD_WINSDK_INCLUDE_WINRT)
        if(${_dir_var})
            defold_log("sdk_windows: WindowsKits include: ${${_dir_var}}")
            list(APPEND CMAKE_INCLUDE_PATH "${${_dir_var}}")
            list(APPEND _DEFOLD_INCLUDE_FLAGS "/I\"${${_dir_var}}\"")
            list(APPEND _DEFOLD_INC_DIRS "${${_dir_var}}")
            # Cache include dirs
            if(_dir_var STREQUAL "DEFOLD_WINSDK_INCLUDE_SHARED")
                set(DEFOLD_WINSDK_INCLUDE_SHARED "${DEFOLD_WINSDK_INCLUDE_SHARED}" CACHE PATH "WindowsKits shared include directory" FORCE)
            elseif(_dir_var STREQUAL "DEFOLD_WINSDK_INCLUDE_UCRT")
                set(DEFOLD_WINSDK_INCLUDE_UCRT "${DEFOLD_WINSDK_INCLUDE_UCRT}" CACHE PATH "WindowsKits UCRT include directory" FORCE)
            elseif(_dir_var STREQUAL "DEFOLD_WINSDK_INCLUDE_UM")
                set(DEFOLD_WINSDK_INCLUDE_UM "${DEFOLD_WINSDK_INCLUDE_UM}" CACHE PATH "WindowsKits UM include directory" FORCE)
            elseif(_dir_var STREQUAL "DEFOLD_WINSDK_INCLUDE_WINRT")
                set(DEFOLD_WINSDK_INCLUDE_WINRT "${DEFOLD_WINSDK_INCLUDE_WINRT}" CACHE PATH "WindowsKits WinRT include directory" FORCE)
            endif()
        endif()
    endforeach()

    if(_DEFOLD_INCLUDE_FLAGS)
        string(JOIN " " _DEFOLD_INCLUDE_FLAGS_STR ${_DEFOLD_INCLUDE_FLAGS})
        # Apply include directories to targets (SYSTEM to reduce warnings) when available
        if(_DEFOLD_INC_DIRS AND NOT CMAKE_SCRIPT_MODE_FILE AND TARGET defold_sdk)
            target_include_directories(defold_sdk SYSTEM INTERFACE ${_DEFOLD_INC_DIRS})
        endif()
        # Propagate to try_compile checks
        set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${_DEFOLD_INCLUDE_FLAGS_STR}")
        set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${_DEFOLD_INCLUDE_FLAGS_STR}")
        set(_DEFOLD_TRY_VARS CMAKE_C_FLAGS CMAKE_CXX_FLAGS)
        if(DEFINED CMAKE_TRY_COMPILE_PLATFORM_VARIABLES)
            list(APPEND CMAKE_TRY_COMPILE_PLATFORM_VARIABLES ${_DEFOLD_TRY_VARS})
            list(REMOVE_DUPLICATES CMAKE_TRY_COMPILE_PLATFORM_VARIABLES)
        else()
            set(CMAKE_TRY_COMPILE_PLATFORM_VARIABLES "${_DEFOLD_TRY_VARS}")
        endif()
    endif()
endif()

# Locate MSVC include directory (for vcruntime.h) and add it to include paths and compiler flags
set(DEFOLD_MSVC_INCLUDE_DIR "")
if(NOT DEFOLD_MSVC_INCLUDE_DIR AND DEFOLD_MSVC_LIB_DIR)
    # Try derive include from located MSVC lib dir
    get_filename_component(_lib_parent "${DEFOLD_MSVC_LIB_DIR}" DIRECTORY)      # .../lib
    get_filename_component(_msvc_ver_dir "${_lib_parent}" DIRECTORY)            # .../VC/Tools/MSVC/<ver>
    set(_cand_inc "${_msvc_ver_dir}/include")
    if(EXISTS "${_cand_inc}/vcruntime.h")
        set(DEFOLD_MSVC_INCLUDE_DIR "${_cand_inc}")
    endif()
endif()

if(NOT DEFOLD_MSVC_INCLUDE_DIR AND _FOUND_MSVC_CL)
    _defold_locate_msvc_include_dir_from_cl("${_FOUND_MSVC_CL}" _msvc_inc_dir)
    if(_msvc_inc_dir)
        set(DEFOLD_MSVC_INCLUDE_DIR "${_msvc_inc_dir}")
    endif()
endif()

if(NOT DEFOLD_MSVC_INCLUDE_DIR)
    # Fallback: search common Visual Studio roots (packaged and system)
    set(_MSVC_INC_CANDIDATE_ROOTS "")
    if(DEFINED DEFOLD_SDK_ROOT)
        set(_SDKS_DIR "${DEFOLD_SDK_ROOT}/ext/SDKs")
        if(EXISTS "${_SDKS_DIR}")
            list(APPEND _MSVC_INC_CANDIDATE_ROOTS "${_SDKS_DIR}")
            file(GLOB _vs_children_inc2 "${_SDKS_DIR}/*")
            foreach(_child IN LISTS _vs_children_inc2)
                if(IS_DIRECTORY "${_child}")
                    list(APPEND _MSVC_INC_CANDIDATE_ROOTS "${_child}")
                endif()
            endforeach()
        endif()
    endif()
    list(APPEND _MSVC_INC_CANDIDATE_ROOTS
        "C:/Program Files (x86)/Microsoft Visual Studio/2022/BuildTools"
        "C:/Program Files (x86)/Microsoft Visual Studio/2022/Community"
        "C:/Program Files (x86)/Microsoft Visual Studio/2019/BuildTools"
        "C:/Program Files (x86)/Microsoft Visual Studio/2019/Community"
    )
    list(REMOVE_DUPLICATES _MSVC_INC_CANDIDATE_ROOTS)

    foreach(_root IN LISTS _MSVC_INC_CANDIDATE_ROOTS)
        if(DEFOLD_MSVC_INCLUDE_DIR)
            break()
        endif()
        file(GLOB _msvc_ver_dirs2 "${_root}/VC/Tools/MSVC/*")
        if(_msvc_ver_dirs2)
            list(SORT _msvc_ver_dirs2)
            list(REVERSE _msvc_ver_dirs2)
            foreach(_verdir IN LISTS _msvc_ver_dirs2)
                set(_cand_inc2 "${_verdir}/include")
                if(EXISTS "${_cand_inc2}/vcruntime.h")
                    set(DEFOLD_MSVC_INCLUDE_DIR "${_cand_inc2}")
                    break()
                endif()
            endforeach()
        endif()
    endforeach()
endif()

if(DEFOLD_MSVC_INCLUDE_DIR)
    defold_log("sdk_windows: MSVC include: ${DEFOLD_MSVC_INCLUDE_DIR}")
    list(APPEND CMAKE_INCLUDE_PATH "${DEFOLD_MSVC_INCLUDE_DIR}")
    # Target-scoped include when available
    if(NOT CMAKE_SCRIPT_MODE_FILE AND TARGET defold_sdk)
        target_include_directories(defold_sdk SYSTEM INTERFACE "${DEFOLD_MSVC_INCLUDE_DIR}")
    endif()
    set(DEFOLD_MSVC_INCLUDE_DIR "${DEFOLD_MSVC_INCLUDE_DIR}" CACHE PATH "MSVC include directory (contains vcruntime.h)" FORCE)
    # Propagate to try_compile
    set(CMAKE_C_FLAGS   "${CMAKE_C_FLAGS} /I\"${DEFOLD_MSVC_INCLUDE_DIR}\"")
    set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /I\"${DEFOLD_MSVC_INCLUDE_DIR}\"")
    set(_DEFOLD_TRY_VARS CMAKE_C_FLAGS CMAKE_CXX_FLAGS)
    if(DEFINED CMAKE_TRY_COMPILE_PLATFORM_VARIABLES)
        list(APPEND CMAKE_TRY_COMPILE_PLATFORM_VARIABLES ${_DEFOLD_TRY_VARS})
        list(REMOVE_DUPLICATES CMAKE_TRY_COMPILE_PLATFORM_VARIABLES)
    else()
        set(CMAKE_TRY_COMPILE_PLATFORM_VARIABLES "${_DEFOLD_TRY_VARS}")
    endif()
endif()


# Locate MSVC runtime/libs directory (for LIBCMT.lib etc.) and add to lib paths and linker flags
set(DEFOLD_MSVC_LIB_DIR "")
if(_FOUND_MSVC_CL)
    _defold_locate_msvc_lib_dir_from_cl("${_FOUND_MSVC_CL}" "${_DEFOLD_WIN_ARCH}" _msvc_lib_dir)
    if(_msvc_lib_dir)
        set(DEFOLD_MSVC_LIB_DIR "${_msvc_lib_dir}")
    endif()
endif()

if(NOT DEFOLD_MSVC_LIB_DIR)
    # Try to locate in common Visual Studio roots (packaged and system)
    set(_MSVC_CANDIDATE_ROOTS "")
    if(DEFINED DEFOLD_SDK_ROOT)
        set(_SDKS_DIR "${DEFOLD_SDK_ROOT}/ext/SDKs")
        if(EXISTS "${_SDKS_DIR}")
            list(APPEND _MSVC_CANDIDATE_ROOTS "${_SDKS_DIR}")
            file(GLOB _vs_children "${_SDKS_DIR}/*")
            foreach(_child IN LISTS _vs_children)
                if(IS_DIRECTORY "${_child}")
                    list(APPEND _MSVC_CANDIDATE_ROOTS "${_child}")
                endif()
            endforeach()
        endif()
    endif()
    list(APPEND _MSVC_CANDIDATE_ROOTS
        "C:/Program Files (x86)/Microsoft Visual Studio/2022/BuildTools"
        "C:/Program Files (x86)/Microsoft Visual Studio/2022/Community"
        "C:/Program Files (x86)/Microsoft Visual Studio/2019/BuildTools"
        "C:/Program Files (x86)/Microsoft Visual Studio/2019/Community"
    )
    list(REMOVE_DUPLICATES _MSVC_CANDIDATE_ROOTS)

    foreach(_root IN LISTS _MSVC_CANDIDATE_ROOTS)
        if(DEFOLD_MSVC_LIB_DIR)
            break()
        endif()
        file(GLOB _msvc_ver_dirs "${_root}/VC/Tools/MSVC/*")
        if(_msvc_ver_dirs)
            list(SORT _msvc_ver_dirs)
            list(REVERSE _msvc_ver_dirs)
            foreach(_verdir IN LISTS _msvc_ver_dirs)
                foreach(_layout IN "lib/${_DEFOLD_WIN_ARCH}" "lib/onecore/${_DEFOLD_WIN_ARCH}")
                    set(_cand "${_verdir}/${_layout}")
                    if(EXISTS "${_cand}/libcmt.lib")
                        set(DEFOLD_MSVC_LIB_DIR "${_cand}")
                        break()
                    endif()
                endforeach()
                if(DEFOLD_MSVC_LIB_DIR)
                    break()
                endif()
            endforeach()
        endif()
    endforeach()
endif()

if(DEFOLD_MSVC_LIB_DIR)
    defold_log("sdk_windows: MSVC libs: ${DEFOLD_MSVC_LIB_DIR}")
    list(APPEND CMAKE_LIBRARY_PATH "${DEFOLD_MSVC_LIB_DIR}")
    set(DEFOLD_MSVC_LIB_DIR "${DEFOLD_MSVC_LIB_DIR}" CACHE PATH "MSVC library directory (contains LIBCMT.lib)" FORCE)
    # Add to linker flags to affect try_compile checks
    if(NOT DEFINED _DEFOLD_LINK_LIBPATH_FLAGS)
        set(_DEFOLD_LINK_LIBPATH_FLAGS "")
    endif()
    list(APPEND _DEFOLD_LINK_LIBPATH_FLAGS "/LIBPATH:\"${DEFOLD_MSVC_LIB_DIR}\"")
endif()

# Apply collected /LIBPATH flags to all linker types so they take effect early (e.g. during compiler checks)
if(_DEFOLD_LINK_LIBPATH_FLAGS)
    string(JOIN " " _DEFOLD_LINK_LIBPATH_FLAGS_STR ${_DEFOLD_LINK_LIBPATH_FLAGS})
    # Apply to this build (target-scoped) when available
    if(NOT CMAKE_SCRIPT_MODE_FILE AND TARGET defold_sdk)
        target_link_options(defold_sdk INTERFACE ${_DEFOLD_LINK_LIBPATH_FLAGS})
    endif()
    # Propagate to try_compile
    set(CMAKE_EXE_LINKER_FLAGS    "${CMAKE_EXE_LINKER_FLAGS} ${_DEFOLD_LINK_LIBPATH_FLAGS_STR}")
    set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} ${_DEFOLD_LINK_LIBPATH_FLAGS_STR}")
    set(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} ${_DEFOLD_LINK_LIBPATH_FLAGS_STR}")
    set(_DEFOLD_TRY_VARS CMAKE_EXE_LINKER_FLAGS CMAKE_SHARED_LINKER_FLAGS CMAKE_MODULE_LINKER_FLAGS)
    if(DEFINED CMAKE_TRY_COMPILE_PLATFORM_VARIABLES)
        list(APPEND CMAKE_TRY_COMPILE_PLATFORM_VARIABLES ${_DEFOLD_TRY_VARS})
        list(REMOVE_DUPLICATES CMAKE_TRY_COMPILE_PLATFORM_VARIABLES)
    else()
        set(CMAKE_TRY_COMPILE_PLATFORM_VARIABLES "${_DEFOLD_TRY_VARS}")
    endif()
endif()
# Prefer explicit packaged MSVC roots for the current arch (Win32/x64)
if(DEFINED DEFOLD_SDK_ROOT)
    set(_EXPL_MSVC_ROOTS)
    if(_DEFOLD_WIN_ARCH STREQUAL "x86")
        list(APPEND _EXPL_MSVC_ROOTS
            "${DEFOLD_SDK_ROOT}/ext/SDKs/Win32"
            "${DEFOLD_SDK_ROOT}/ext/SDKs/x86")
    else()
        list(APPEND _EXPL_MSVC_ROOTS
            "${DEFOLD_SDK_ROOT}/ext/SDKs/x64"
            "${DEFOLD_SDK_ROOT}/ext/SDKs/Win64")
    endif()
    foreach(_vs IN LISTS _EXPL_MSVC_ROOTS)
        if(EXISTS "${_vs}")
            if(NOT _FOUND_MSVC_CL)
                _defold_detect_msvc_cl_from_vsroot("${_vs}" "${_DEFOLD_WIN_ARCH}" _cl_expl)
                if(_cl_expl)
                    set(_FOUND_MSVC_CL "${_cl_expl}")
                endif()
            endif()
            if(NOT _FOUND_CLANG_CL)
                _defold_detect_clang_cl_from_vsroot("${_vs}" "${_DEFOLD_WIN_ARCH}" _clangcl_expl)
                if(_clangcl_expl)
                    set(_FOUND_CLANG_CL "${_clangcl_expl}")
                endif()
            endif()
        endif()
    endforeach()
endif()
